#include "difftest.h"
#include <dlfcn.h>
#include "mem.h"

CPU_state ref_cpu_state = {.pc = MEMORY_BASE};
void (*ref_difftest_memcpy)(word_t addr, void *buf, size_t n, bool direction) = NULL;
void (*ref_difftest_regcpy)(void *dut, bool direction) = NULL;
void (*ref_difftest_exec)(uint64_t n) = NULL;
void (*ref_difftest_raise_intr)(uint64_t NO) = NULL;

void dut_difftest_init(char *ref_so_file)
{
    assert(ref_so_file != NULL);
    printf("Use Ref %s\n",ref_so_file);
    void *handle;
    handle = dlopen(ref_so_file, RTLD_LAZY);
    assert(handle);

    ref_difftest_memcpy = (void (*)(word_t, void *, size_t, bool))dlsym(handle, "difftest_memcpy");
    assert(ref_difftest_memcpy);

    ref_difftest_regcpy = (void (*)(void *, bool))dlsym(handle, "difftest_regcpy");
    assert(ref_difftest_regcpy);

    ref_difftest_exec = (void (*)(uint64_t))dlsym(handle, "difftest_exec");
    assert(ref_difftest_exec);

    ref_difftest_raise_intr = (void (*)(uint64_t))dlsym(handle, "difftest_raise_intr");
    assert(ref_difftest_raise_intr);

    void (*ref_difftest_init)(int) = (void (*)(int))dlsym(handle, "difftest_init");
    assert(ref_difftest_init);

    LOG("Differential testing: %s", COLOR("ON", GREEN));
    LOG("The result of every instruction will be compared with %s. "
        "This will help you a lot for debugging, but also significantly reduce the performance. "
        "If it is not necessary, you can turn it off in menuconfig.",
        ref_so_file);

    ref_difftest_init(0);
    ref_difftest_memcpy(MEMORY_BASE, guest_to_host(MEMORY_BASE, false), MEMORY_SIZE, DIFFTEST_TO_REF);
    ref_difftest_regcpy(&ref_cpu_state, DIFFTEST_TO_REF);
}